package com.swak.frame.ratelimit.interceptor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.swak.frame.ratelimit.RateLimitAnnotationParser;
import com.swak.frame.ratelimit.config.LimitOperation;

public class RaterAnnotationParserComposite implements RateLimitAnnotationParser {

	private final List<RateLimitAnnotationParser> delegates = new ArrayList<>();

	public RaterAnnotationParserComposite(List<RateLimitAnnotationParser> configurers) {
		addAnnotationParsers(configurers);
	}

	public void addAnnotationParsers(RateLimitAnnotationParser... configurers) {
		if (configurers != null) {
			delegates.addAll(Lists.newArrayList(configurers));
		}
	}

	public void addAnnotationParsers(List<RateLimitAnnotationParser> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.delegates.addAll(configurers);
		}
	}

	@Override
	public boolean isCandidateClass(Class<?> targetClass) {
		for (RateLimitAnnotationParser delegate : delegates) {
			if (delegate.isCandidateClass(targetClass)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public Collection<LimitOperation> parseAnnotations(Class<?> type) {
		Collection<LimitOperation> ops = null;
		for (RateLimitAnnotationParser delegate : delegates) {
			Collection<LimitOperation> annOps = delegate.parseAnnotations(type);
			if (annOps != null) {
				if (ops == null) {
					ops = annOps;
				} else {
					Collection<LimitOperation> combined = new ArrayList<>(ops.size() + annOps.size());
					combined.addAll(ops);
					combined.addAll(annOps);
					ops = combined;
				}
			}
		}
		return ops;
	}

	@Override
	public Collection<LimitOperation> parseAnnotations(Method method, Class<?> targetClass) {
		Collection<LimitOperation> ops = null;
		for (RateLimitAnnotationParser delegate : delegates) {
			Collection<LimitOperation> annOps = delegate.parseAnnotations(method, targetClass);
			if (annOps != null) {
				if (ops == null) {
					ops = annOps;
				} else {
					Collection<LimitOperation> combined = new ArrayList<>(ops.size() + annOps.size());
					combined.addAll(ops);
					combined.addAll(annOps);
					ops = combined;
				}
			}
		}
		return ops;
	}
}
